﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Castle.DynamicProxy;
using System.Diagnostics.Contracts;
using System.Diagnostics;
using NetalBase.Base.Attributes;
using NetalBase.Reflection;

namespace NetalBase.Base
{
	class IAutomatonBaseInterceptor : IInterceptor
	{
		#region IInterceptor Members

		public void Intercept(IInvocation invocation)
		{
			var automaton = invocation.InvocationTarget as IAutomatonBase;

			string eventName = invocation.Method.Name;

			var attr = invocation.Method.GetCustomAttributes(typeof(RaiseEventMethodAttribute), false);

			// state transitions are set
			invocation.Proceed();
			if (attr.Length > 0)
			{
				string readableEventName = eventName.TrimStart('_');
				Log.Logger.WriteInternalEvent(automaton, readableEventName);
				automaton.Events2RelatedAutomata.Add(() =>
					{
						movingAutomaton2NextState(automaton, eventName);
						ReflectionHelper.FireEvent(automaton, readableEventName, invocation.Arguments);
					});
			}
			else
			{
				Log.Logger.WriteExternalEvent(automaton, eventName);

				// calling state definition method			
				automaton.State.GetType().GetMethod(eventName).Invoke(automaton.State, invocation.Arguments);

				movingAutomaton2NextState(automaton, eventName);
			}
		}
		#endregion

		void movingAutomaton2NextState(IAutomatonBase automaton, string eventName)
		{
			//  moving to next state (so the automaton that causes other automata to
			// transition, moves to its target state before them).
			automaton.ToNextState(eventName);

			Log.Logger.WriteCurrentState(automaton);

			// calling state action
			automaton.CallCurrentStateAction();

			// pass events to related automata
			automaton.ProcessRelatedEvents();
		}
	}
}
